﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;

namespace Nirvana
{
    [DisallowMultipleComponent]
    [AddComponentMenu("Nirvana/Animator/Animator Event Dispatcher")]
    public class AnimatorEventDispatcher : MonoBehaviour
    {
        private Dictionary<string, SignalEvent> signalEventMap = new Dictionary<string, SignalEvent>();

        private sealed class AnimatorEvent
        {
            public bool isStop;
            public SignalHandle signalHandle;
            public Action<string, AnimatorStateInfo> callback;
            public void OnStart(object[] objs)
            {
                this.callback((string)objs[0], (AnimatorStateInfo)objs[1]);
            }
            public void OnStop(string evenname, AnimatorStateInfo info)
            {
                this.isStop = true;
                this.signalHandle.Dispose();
            }
            public bool IsStop()
            {
                return isStop;
            }
            public void OnComplete(string eventname, AnimatorStateInfo info)
            {
                this.callback(eventname, info);
                this.signalHandle.Dispose();
            }
        }

        public IEnumerator WaitEvent(string eventname)
        {
            var evet = new AnimatorEvent();
            evet.isStop = false;
            evet.signalHandle = null;
            evet.signalHandle = this.ListenEvent(eventname, evet.OnStop);
            return new WaitUntil(evet.IsStop);
        }

        public void WaitEvent(string eventname,Action<string,AnimatorStateInfo> cb)
        {
            var _event = new AnimatorEvent();
            _event.callback = cb;
            Assert.IsNotNull<Action<string, AnimatorStateInfo>>(_event.callback);
            _event.signalHandle = null;
            _event.signalHandle = this.ListenEvent(eventname, _event.OnComplete);
        }


        public SignalHandle ListenEvent(string eventname,Action<string, AnimatorStateInfo> cb)
        {
            AnimatorEvent _event = new AnimatorEvent();
            _event.callback = cb;
            SignalEvent signalEvent;
            if(!this.signalEventMap.TryGetValue(eventname,out signalEvent))
            {
                signalEvent = new SignalEvent();
                this.signalEventMap.Add(eventname, signalEvent);
            }
            return signalEvent.Create(new SignalDelegate(_event.OnStart));
        }

        public void Excute(string eventname,string parmas, AnimatorStateInfo info)
        {
            SignalEvent signalEvent;
            if(this.signalEventMap.TryGetValue(eventname,out signalEvent))
            {
                signalEvent.Excute(parmas, info);
            }
        }
    }
}

